#include "usart2.h"

/************************************************************************
*函数名：USART2_Config
*函数功能：对串口2模块进行初始化配置
*函数参数：u32 bps，波特率
*函数返回值：无
*函数说明：
*************************************************************************/
static void USART2_Config(u32 bps)
{
	/*配置USART控制器*/
	//波特率寄存器
	float USART_DIV;
	u32 DIV_M;//整数部分
	u32 DIV_F;//小数部分
	USART2->CR1 = 0;
	u32 OVER8 = ((USART2->CR1)>>15);
	USART_DIV = 42000000.0/(8*bps*(2-OVER8));//APB1时钟频率42Mhz
	DIV_M = USART_DIV;
	DIV_F = (USART_DIV - DIV_M)*16;
	USART2->BRR = (DIV_M<<4|DIV_F);
	/*当波特率bps = 115200且过采样16倍时，USART_DIV ≈ 22.7865，
	 * 约等于二进制的10110.1100。因此，最后给波特率寄存器所赋的值为101101100*/

	//控制寄存器1——USART使能、发送器和接收器使能
	USART2->CR1 |= (1<<2|1<<3|1<<13);
}

/************************************************************************
*函数名：USART2_Init
*函数功能：对串口2连接的GPIO口进行初始化配置
*函数参数：无
*函数返回值：无
*函数说明：
				USART2_TX——PA2——复用功能模式，推挽，100MHz
				USART2_RX——PA3——复用功能模式，推挽，100MHz
*************************************************************************/
void USART2_Init(void)
{
	/*使能GPIOA和USART2时钟*/
	RCC->AHB1ENR |= (1<<0);//使能GPIOA时钟
	RCC->APB1ENR |= (1<<17);//使能USART2时钟

	/*配置GPIO控制器*/
	//模式寄存器——复用功能模式 10
	GPIOA->MODER &= ~(3<<2*2);
	GPIOA->MODER |= (2<<2*2);
	GPIOA->MODER &= ~(3<<3*2);
	GPIOA->MODER |= (2<<3*2);

	//输出类型寄存器——推挽 0
	GPIOA->OTYPER &= ~(3<<2);//PA2 PA3清零

	//输出速度寄存器——高速 11
	GPIOA->OSPEEDR |= (15<<2*2);

	//复用功能低位寄存器——AF7 0111
	GPIOA->AFR[0] &= ~(0xff<<8);
	GPIOA->AFR[0] |= (0x77<<8);

	/*配置USART1控制器*/
	USART2_Config(115200);//波特率设置为115200，并使能USART2和收发器

	/*开启中断*/
	//在CR1开启中断
	USART2->CR1 |= (1<<5);//使能接收中断
	USART2->CR1 |= (1<<4);//使能空闲中断
	//设置中断优先级
	NVIC_SetPriority(USART2_IRQn,NVIC_EncodePriority(7-2,1,3));//给USART2设置优先级为(1,3)
	//使能中断源
	NVIC_EnableIRQ(USART2_IRQn);
}

/************************************************************************
*函数名：USART2_IRQHandler（不可更改）
*函数功能：USART2中断服务函数
*函数参数：无
*函数返回值：无
*函数说明：此函数需要用到一个USART_STRUCT结构体
*类型变量usart2_struct，且此变量在其他文件也需要使用。
*************************************************************************/
USART_STRUCT usart2_struct;

void USART2_IRQHandler(void)
{
	u8 data;

	if (USART2->SR & (1<<5))//如果是接收中断
	{
		USART2->SR &= ~(1<<5);//RXNE清零
		data = USART2->DR;//把接收到的字节数据写入变量data
		usart2_struct.recvdata[usart2_struct.count] = data;//向数据数组存入这一字节
		usart2_struct.count++;//数组下标增加
	}
	if (USART2->SR & (1<<4))//如果是空闲中断
	{
		USART2->DR;//读SR+读DR可以把IDLE清零
		usart2_struct.recvdata[usart2_struct.count] = '\0';//补充字符串末尾
		usart2_struct.count = 0;//数组下标清零
		usart2_struct.flag = 1;//数据数组已经写入完成，标志位置1
	}
}

/************************************************************************
*函数名：USART2_SendByte
*函数功能：用串口2发送一个字节的数据
*函数参数：u8 bytedata，要发送的字节
*函数返回值：无
*函数说明：
*************************************************************************/
void USART2_SendByte(u8 bytedata)
{
	while((USART2->SR & (1<<7)) == 0);//当数据未传输到发送移位寄存器时，进行循环
	USART2->DR = bytedata;
}


/************************************************************************
*函数名：USART2_SendString
*函数功能：用串口2发送一个字符串的数据
*函数参数：u8 *str，要发送的字符串
*函数返回值：无
*函数说明：
*************************************************************************/
void USART2_SendString(u8 *pstr)
{
	while(*pstr != '\0')
	{
		USART2_SendByte(*pstr);
		pstr++;
	}
}


/************************************************************************
*函数名：USART2_ReceiveByte
*函数功能：用串口2接收一个字节的数据
*函数参数：无
*函数返回值：u8 bytedata，要接收的字节
*函数说明：
*************************************************************************/
u8 USART2_ReceiveByte(void)
{
	u8 bytedata;
	while((USART2->SR & (1<<5)) == 0);//当数据未传输到RDR时，进行循环
	bytedata = USART2->DR;
	return bytedata;
}



